package cn.iocoder.yudao.module.iot.gateway.protocol.custom.xiaoan.tcp.codec;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils;
import cn.iocoder.yudao.module.iot.gateway.codec.IotDeviceMessageCodec;
import cn.iocoder.yudao.module.iot.gateway.protocol.custom.xiaoan.tcp.codec.parser.XiaoAnMessageParser;
import io.vertx.core.buffer.Buffer;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

@Slf4j
@Component
public class XiaoAnTcpMessageCodec implements IotDeviceMessageCodec {

    public static final String TYPE = "TCP_XA";

    /**
     * 协议魔术字，用于协议识别
     */
    private static final short MAGIC_NUMBER = (short) 0xAA55;
    /**
     * 协议头部固定长度（魔术字(2) + 命令字(1) + 序列号(1) + 长度(2)）
     */
    private static final int HEADER_FIXED_LENGTH = 6;

    /**
     * 最小消息长度（头部）
     */
    private static final int MIN_MESSAGE_LENGTH = HEADER_FIXED_LENGTH;

    @Resource
    private List<XiaoAnMessageParser> messageParsers;

    @Override
    public String type() {
        return TYPE;
    }

    @Override
    public IotDeviceMessage decode(byte[] bytes) {
        // 根据小安协议格式解析数据
        Assert.notNull(bytes, "待解码数据不能为空");
        Assert.isTrue(bytes.length >= MIN_MESSAGE_LENGTH, "数据包长度不足");

        try {
            Buffer buffer = Buffer.buffer(bytes);
            // 解析协议头部和消息内容
            int index = 0;
            // 1. 验证魔术字
            short magic = buffer.getShort(index);
            index += 2;
            Assert.isTrue(magic == MAGIC_NUMBER, "无效的协议魔术字: " + magic);

            // 2. 命令字
            byte cmd = buffer.getByte(index++);

            // 3. 序列号
            byte seq = buffer.getByte(index++);

            // 4. 长度
            int bodyLen = buffer.getShort(index);
            index += 2;
            int messageLen = bodyLen + HEADER_FIXED_LENGTH;
            Assert.isTrue(messageLen == buffer.length(),
                    "消息长度不匹配，期望: " + messageLen + ", 实际: " + buffer.length());

            // 5. 解析消息体
            return parseMessageBody(buffer, index, cmd, seq);
        } catch (Exception e) {
            log.error("[decode][TCP 二进制消息解码失败，数据长度: {}, buffer:{}]", bytes.length, HexUtil.encodeHexStr(bytes));
            throw new RuntimeException("TCP 二进制消息解码失败: " + e.getMessage(), e);
        }
    }


    @Override
    public byte[] encode(IotDeviceMessage message) {
        // 按照小安协议格式编码消息
        // 示例中简化处理
        // 将message组装成二进制数据
        Assert.notNull(message, "消息不能为空");
        Assert.notBlank(message.getMethod(), "消息方法不能为空");
        try {
            // 1. 判断是否为响应消息
            boolean isReplay = isReplay(message);
            // 2. 构建消息体
            byte[] bodyData = buildMessageBody(message, isReplay);
            // 3. 构建完整消息
            return buildCompleteMessage(message, isReplay, bodyData);
        } catch (Exception e) {
            log.error("[encode][TCP 二进制消息编码失败，消息: {}]", message, e);
            throw new RuntimeException("TCP 二进制消息编码失败: " + e.getMessage(), e);
        }
    }


    /**
     * 解析消息体
     */
    private IotDeviceMessage parseMessageBody(Buffer buffer, int startIndex, byte cmd, byte seq) {
        log.info("[parseMessageBody][cmd: {}, seq: {}, buffer: {}]", cmd, seq, HexUtil.encodeHexStr(buffer.getBytes()));
        // 通过 Spring 管理的解析器列表查找支持的解析器
        for (XiaoAnMessageParser parser : messageParsers) {
            if (parser.supports(XiaoAnCmdTypeEnum.of(cmd))) {
                return parser.parse(buffer, startIndex, cmd, seq);
            }
        }
        // 未找到支持的解析器
        throw new IllegalArgumentException("不支持的命令类型: " + cmd);
    }

    /**
     * 构建消息体
     *
     */
    private byte[] buildMessageBody(IotDeviceMessage message, boolean isReplay) {
        Buffer bodyBuffer = Buffer.buffer();
        // 消息回复 只处理data
        if (isReplay) {
            // data
            if (message.getData() != null) {
                bodyBuffer.appendBytes(JsonUtils.toJsonByte(message.getData()));
            }
        } else {
            // 请求消息只处理 params 参数
            // TODO @haohao：如果为空，是不是得写个长度 0 哈？
            if (message.getParams() != null) {
                bodyBuffer.appendBytes(JsonUtils.toJsonByte(message.getParams()));
            }
        }
        return bodyBuffer.getBytes();
    }

    private boolean isReplay(IotDeviceMessage message) {
        // 判断是否为响应消息：有响应码或响应消息时为响应
        return message.getCode() != null;
    }

    /**
     * 构建完整消息
     */
    private byte[] buildCompleteMessage(IotDeviceMessage message, boolean isReplay, byte[] bodyData) {
        Buffer buffer = Buffer.buffer();
        byte bodyLength = (byte) bodyData.length;
        byte cmd = XiaoAnCmdTypeEnum.WILD.getCode();
        byte seq = Byte.parseByte(message.getRequestId());

        // 1. 写入协议头部
        buffer.appendShort(MAGIC_NUMBER);

        if (isReplay){
            // 请求参数
            Map<String, Object> paramMap= (Map<String, Object>) message.getParams();
            cmd= Byte.parseByte(message.getMethod());
        }else{
            // 响应参数
            seq = Byte.parseByte(StrUtil.isNotBlank(message.getRequestId()) ? message.getRequestId()
                    : IotDeviceMessageUtils.generateMessageId());
        }
        // 2. 命令字
        buffer.appendByte(cmd);
        // 3. 序列号
        buffer.appendByte(seq);
        // 4. 长度
        buffer.appendShort(bodyLength);
        // 5. 写入消息体
        buffer.appendBytes(bodyData);
        return buffer.getBytes();
    }


}
